#include "coletorpcp.h"

#include "utils/pluginutil.h"
#include "utils/network.h"
#include "dao/operacaodao.h"
#include "dao/databaseexception.h"

#include "utils/log.h"

#include <stdlib.h>

ColetorPCP::ColetorPCP(QObject *parent) :
    QObject(parent)
{
    LOGD("BEGIN");
    cache = new Cache(this);

    db = new DB(this);
    m_conf = new Conf(CONF_FILE_NAME, 0);

    departamentoDAO = new DepartamentoDAO();

    operacaoDAO = new OperacaoDAO();
    operacaoDAO->setPageSize(OPERACOES_POR_PAGINA);

    produtoDAO = new ProdutoDAO();
    produtoDAO->setPageSize(PRODUTOS_POR_PAGINA);

    panelaDAO = new PanelaDAO();
    panelaDAO->setPageSize(PANELAS_POR_PAGINA);

    pluginWorker = new PluginWorker(0,this);
//    pluginWorker->runInBackground(SLOT(doPluginReload()));
    LOGD("END");
}

ColetorPCP::~ColetorPCP()
{
    LOGD("BEGIN");
    delete departamentoDAO;
    delete operacaoDAO;
    delete produtoDAO;
    delete panelaDAO;

    pluginWorker->stop();
    delete pluginWorker;
    LOGD("END");
}

Conf* ColetorPCP::conf()
{
    LOGD("BEGIN");
    LOGD("END");
    return m_conf;
}

void ColetorPCP::setConf(Conf* conf)
{
    LOGD("BEGIN");
    if(this->m_conf!=conf) {
        this->m_conf = conf;
        emit confChanged();
    }
    LOGD("END");
}

void ColetorPCP::load_all_data()
{
    LOGD("BEGIN");
    ColetorWorker *worker = new ColetorWorker(0,this);
    worker->runInBackground(SLOT(doLoadAllData()) );
    LOGD("END");
}

void ColetorPCP::doLoadAllData()
{
    LOGD("BEGIN");
    cache->clear();

    try {
        get_departamento();
        get_operacoes();

        QList<QObject*> produtos = get_produtos(FILTRO_TODOS);

        for(int i=0; i<produtos.length(); i++) {
            Produto *produto = (Produto *)produtos.at(i);
            QString key = KEY_PRODUTOS_PREFFIX + produto->descricao();
            cache->append(key,produto);
        }

        get_panelas();

        emit dataLoaded();
    } catch (DatabaseException &e) {
        emit databaseConnectionError(_MSG_ERRO_CONEXAO_BD);
    }
    LOGD("END");
}

void ColetorPCP::testar_rede()
{
    LOGD("BEGIN");
    ColetorWorker *worker = new ColetorWorker(0,this);
    worker->runInBackground(SLOT(doNetworkTest()) );
    LOGD("END");
}

void ColetorPCP::doNetworkTest() {
    LOGD("BEGIN");
    bool result = Network::checkInterface(NETWORK_INTERFACE_NAME);

    if(!result) {
        emit networkError(_MSG_ERRO_CONEXAO_REDE);
    } else {
        emit networkSuccess();
    }
    LOGD("END");
}

void ColetorPCP::testar_bd()
{
    LOGD("BEGIN");
    ColetorWorker *worker = new ColetorWorker(0,this);
    worker->runInBackground(SLOT(doDatabaseTest()) );
    LOGD("END");
}

void ColetorPCP::doDatabaseTest() {
    LOGD("BEGIN");
    int retries = 4;

    db->setHostName(m_conf->get_primary_database_host());
    db->setDatabaseName(m_conf->get_primary_database_name());
    db->setUserName(m_conf->get_primary_database_user());
    db->setPassword(m_conf->get_primary_database_password());

    for(int i=0; i<retries; i++) {
        if(db->connect()) {
            sleep(1);
            break;
        }
        LOGD("RETRY");
        sleep(5);
    }

    if(!db->connect()) {
        emit databaseConnectionError(_MSG_ERRO_CONEXAO_BD);
    } else {
        emit databaseConnectionSuccess();
    }
    LOGD("END");
}

void ColetorPCP::doShutdown() {
    LOGD("BEGIN");
    sleep(1);
    on_exit();

    system("poweroff");
    LOGD("END");
}

void ColetorPCP::desligar()
{
    LOGD("BEGIN");
    ColetorWorker *worker = new ColetorWorker(0,this);
    worker->runInBackground(SLOT(doShutdown()) );
    LOGD("END");
}

QString ColetorPCP::get_plataforma()
{
    LOGD("BEGIN");
    LOGD("END");
    return m_conf->get_plataforma().toUpper();
}

QString ColetorPCP::get_version()
{
    LOGD("BEGIN");
    QFile file(VERSION_FILE_NAME);

    if(!file.exists()) {
        LOGD("END");
        return "000000.000";
    }

    char buffer[128];
    memset(buffer,0,sizeof(buffer));

    file.open(QFile::ReadOnly);
    file.readLine(buffer,127);
    file.close();

    LOGD("END");
    return QString(buffer);
}

QString ColetorPCP::get_departamento()
{
    LOGD("BEGIN");
    int idDepartamento = m_conf->get_id_departamento().toInt();

    if(!cache->contains(KEY_DEPARTAMENTO)) {
        cache->append(KEY_DEPARTAMENTO,departamentoDAO->findById(idDepartamento));
    }

    QList<QObject*> list = cache->value(KEY_DEPARTAMENTO);

    QString result;
    if(!list.isEmpty()) {
        result = ((Departamento *)list[0])->descricao();
    }

    LOGD("END");
    return result;
}

QList<QObject *> ColetorPCP::get_operacoes(int numero_pagina)
{
    LOGD("BEGIN");
    if(!cache->contains(KEY_OPERACOES)) {
        QString where("id_departamento = "+m_conf->get_id_departamento());
        GenericListModel *operacoes = operacaoDAO->findAll(where);
        cache->set(KEY_OPERACOES,operacoes->getEntries());
        delete operacoes;
    }

    QList<QObject *> result = getListFromCache(KEY_OPERACOES,numero_pagina,OPERACOES_POR_PAGINA);

    LOGD("END");
    return result;
}

int ColetorPCP::get_total_paginas_operacoes()
{
    LOGD("BEGIN");
    int result = numPaginas(get_operacoes().length(),OPERACOES_POR_PAGINA);

    LOGD("END");
    return result;
}

QList<QObject *> ColetorPCP::get_produtos(QString filtro, int numero_pagina)
{
    LOGD("BEGIN");
    QString key = KEY_PRODUTOS_PREFFIX + filtro.toUpper();

    if(!cache->contains(key)) {
        QString filtroLetra("UPPER(p.descricao) like ");

        if(filtro == FILTRO_TODOS) {
            filtroLetra.append("'%%'");
        } else {
            filtroLetra.append("UPPER('" + filtro + "%%')");
        }

        QString where("id_departamento = "+ m_conf->get_id_departamento() + " and " + filtroLetra);
        GenericListModel *produtos = produtoDAO->findAll(where);
        cache->set(key,produtos->getEntries());
        delete produtos;
    }

    QList<QObject *> result = getListFromCache(key,numero_pagina,PRODUTOS_POR_PAGINA);

    LOGD("END");
    return result;
}

int ColetorPCP::get_total_paginas_produtos(QString filtro)
{
    LOGD("BEGIN");
    int result = numPaginas(get_produtos(filtro).length(),PRODUTOS_POR_PAGINA);

    LOGD("END");
    return result;
}

QList<QObject *> ColetorPCP::get_panelas(int numero_pagina)
{
    LOGD("BEGIN");
    if(!cache->contains(KEY_PANELAS)) {
        QString where("id_departamento = "+m_conf->get_id_departamento());
        GenericListModel *panelas = panelaDAO->findAll(where);
        cache->set(KEY_PANELAS,panelas->getEntries());
        delete panelas;
    }

    QList<QObject *> result = getListFromCache(KEY_PANELAS,numero_pagina,PANELAS_POR_PAGINA);

    LOGD("END");
    return result;
}

int ColetorPCP::get_total_paginas_panelas()
{
    LOGD("BEGIN");
    int result = numPaginas(cache->get(KEY_PANELAS).length(),PANELAS_POR_PAGINA);

    LOGD("END");
    return result;
}

void ColetorPCP::on_exit()
{
    LOGD("BEGIN");
    db->closeConnection();
    LOGD("END");
}

int ColetorPCP::numPaginas(int count, int pageSize)
{
    LOGD("BEGIN");
    int num = count/pageSize;

    if(count % pageSize) {
        ++num;
    }

    LOGD("BEGIN");
    return num;
}

QList<QObject*> ColetorPCP::getListFromCache(QString cacheKey, int numeroPagina, int pageSize)
{
    LOGD("BEGIN");
    if(numeroPagina == 0) {
        LOGD("END");
        return cache->get(cacheKey);
    }

    int skip = pageSize * (numeroPagina - 1);

    LOGD("END");
    return subList(cache->get(cacheKey),skip,pageSize);
}

QList<QObject*> ColetorPCP::subList(QList<QObject*> list, int begin, int count)
{
    LOGD("BEGIN");
    QList<QObject *> newList;

    for(int i=begin; (i<list.length()) && (i<(begin+count)); i++) {
        newList.append(list.at(i));
    }

    LOGD("END");
    return newList;
}

void ColetorPCP::reloadTouchPlugin() {
    LOGD("BEGIN");
    PluginUtil::reloadTouchPlugin();
    LOGD("END");
}

QString ColetorPCP::interface_type() {
    LOGD("BEGIN");
    LOGD("END");
    return m_conf->get_interface_type().toUpper();
}
